const rootPath = "D:\\WorkStation\\projects\\develop-ncc1.0\\src";
// const ANA_PATH = "D:\\WorkStation\\projects\\develop-ncc1.0\\src\\epmp\\common\\components\\RuleDom\\index.js";
const ANA_PATH = "D:\\WorkStation\\projects\\develop-ncc1.0\\src\\epmp\\*\\*\\*\\index.js";
const writeConfigJSON = true;



const path = require("node:path");
const fs = require("node:fs");
const glob = require("glob");
const EMPTY_LINE_TAG = "@EMPTY_LINE@";
consoleLog("======run========");
analysisPages();
debugger;

function analysisPages() {
  const entries = glob.sync(ANA_PATH.replaceAll("\\", "/"));
  let count = 0;
  const log = {
    importEpmpLog: [],
    errLog: [],
  };
  for (const [i, entry] of entries.entries()) {
    console.clear();
    console.log(`${(((i + 1) / entries.length) * 100).toFixed(2)}%`);
    const analysisedFile = new Set();
    if (writeConfigJSON) {
      const configJSONPath = path.resolve(path.dirname(entry), "config.json");
      const configJSONExits = fs.existsSync(configJSONPath);
      if (!configJSONExits) {
        continue;
      }
      const configJSON = require(configJSONPath);
      
      const dependModuleName = new Set();
      const dependjs = new Set();
      if (entry.indexOf("epmp\\common") < 0) {
        dependjs.add("../../../../epmp/common/configNew/globalSetting/index.js"); 
      }
      analysisFile(entry, dependModuleName, dependjs, analysisedFile, log);
      
      const fillArrProp = (jsonObj, arrayKey) => {
        if (!jsonObj[arrayKey]) {
          jsonObj[arrayKey] = [];
        }
        if (!Array.isArray(jsonObj[arrayKey])) {
          jsonObj[arrayKey] = [jsonObj[arrayKey]];
        }
      }
      
      if (configJSONExits) {
        fillArrProp(configJSON, "dependModuleName");
        fillArrProp(configJSON, "dependjs");
        if (
          (new Set([...dependjs, ...configJSON.dependjs])).size !== configJSON.dependjs.length ||
          (new Set([...dependModuleName, ...configJSON.dependModuleName])).size !== configJSON.dependModuleName.length
        ) {
          configJSON.dependModuleName = [...dependModuleName];
          configJSON.dependjs = [...dependjs];
          delete configJSON.template;
          fs.writeFileSync(configJSONPath, JSON.stringify(configJSON, null, 2).replaceAll("\n", "\r\n"));
        }
      } 
    } else {
      const dependModuleName = new Set();
      const dependjs = new Set();
      dependjs.add("../../../../epmp/common/configNew/globalSetting/index.js");
      analysisFile(entry, dependModuleName, dependjs, analysisedFile, log);
    }
  }
  writeLog(log.errLog.join("\n"));
}

function analysisFile(
  filePath,
  dependModuleName,
  dependjs,
  analysisedFile,
  log
) {
  const formatPath = filePath.replaceAll("\\", "/");
  const logFilePath = filePath.split("\\src\\")[1].split("\\").join("/");
  if (analysisedFile.has(formatPath)) {
    consoleLog(logFilePath, "!!!!!!!!!!!!已经解析过，跳过!!!!!!!!!!!!!!\n\r");
    return;
  }
  consoleLog("\n\r>>>>>>>>>>开始解析", logFilePath, "文件<<<<<<<<<<<<<<<");
  analysisedFile.add(formatPath);
  try {
    const data = fs.readFileSync(formatPath);
    const text = data.toString();
    const lines = text.split("\r\n");

    let importShort = "";
    let importEpmp = false;
    let hasChangedText = false;
    let firstCodeLine = -1;
    let importedPath = new Set();
    for (const [lineNumber, lineValue] of lines.entries()) {
      const line = lineValue.trim();
      const importIndex = line.indexOf("import");
      const formatLine = getFormatLine(line);
      if (
        importShort !== "" ||
        (importIndex === 0 && line[importIndex + 6] === " ")
      ) {
        importShort = `${importShort}${line}`;
        if (firstCodeLine < 0) {
          firstCodeLine = lineNumber;
        }
        if (isLegalImport(importShort)) {
          //一个合法的import语句
          const singleLineImport = formatImport(importShort);
          let importPath = getImportPath(singleLineImport);
          consoleLog(`第${lineNumber + 1}行${logFilePath}解析到合法的import语句${singleLineImport}, from = , ${importPath}`);

          let importAbsPath = "";
          //如果是相对路径并且不在public目录中，递归解析那个文件
          if (importPath.startsWith(".")) {
            dealRelativePath(formatPath, importPath, dependModuleName, dependjs, analysisedFile, log, lineNumber, lines, importedPath, logFilePath, singleLineImport, () => {
              hasChangedText = true;
            });
          } else if (importPath === "epmp" || importPath === "epmp/common/group/components") {
            //如果from完全等于epmp，则标记一下，后面将epmp.EpmpUtil替换为$util
            importEpmp = true;
            lines[lineNumber] = EMPTY_LINE_TAG;
            hasChangedText = true;
            //记录到日志文件，后续手动改
            consoleLog(`第${lineNumber+1}行${logFilePath}导入了epmp，直接删除该行`);
          } else if (importPath.indexOf("epmp") >= 0) {
            if (importPath.indexOf("epmp/exports/components") >= 0) {
              consoleLog(`第${lineNumber + 1}行，${logFilePath}导入了epmp公共组件${importPath},需要读取这个公共组件的dependjs并添加到节点的dependjs中`);
              importPath = importPath.replace(
                "exports/components",
                "common/components"
              );
            }
            addImportInfoToConfig(importPath, dependModuleName, dependjs);
          } else if (
            importPath.indexOf("ufoe") >= 0 ||
            importPath.indexOf("ufoc") >= 0 ||
            importPath.indexOf("uap") >= 0
          ) {
            if (importPath === "ufoe/exports/components/Mselect") {
              importPath = "ufoe/common/components/Mselect";
              lines[lineNumber] = line.replace("ufoe/exports/components/Mselect", "ufoe/common/components/Mselect")
            }
            addImportInfoToConfig(importPath, dependModuleName, dependjs);
          }
          importedPath.add(importPath);
          importShort = "";
        }
      }
      if ((formatLine.startsWith("const") || formatLine.startsWith("let")) && line.endsWith("epmp;")) {
        const mns = line
          .split("{")[1]
          .split("}")[0]
          .split(",")
          .map((mn) => mn.trim());
        lines[lineNumber] = "";
        for (let mn of mns) {
          if (mn === "EpmpUtils" || mn === "EpmpConst" || mn === "") {
            continue;
          }
          let importName = mn.trim();
          
          const moduleNamePathMap = {
            LargeDocSortBox: "epmp/common/components/LargeDocSort",
            CreateCenterReport: "epmp/common/centerReport/createCenterReport",
            YSHandsontable: `epmp/common/components/ys_Handsontable`,
            CreateCenterReportUtils: `epmp/common/centerReport/utils`,
          };
          let importPath = moduleNamePathMap[mn] || `epmp/common/components/${mn}`;
          if (importName === "printClient") {
            importPath = `epmp/common/components/PrintService`;
            importName = `{printClient}`;
          }
          if (importName === "CreateCenterReportUtils") {
            importName = `* as CreateCenterReportUtils`;
          }
          if (importedPath.has(importPath)) {
            continue;
          }
          const importShort = `import ${importName} from "${importPath}";`;
          lines[lineNumber] += `${importShort}\r\n`;
          addImportInfoToConfig(importPath, dependModuleName, dependjs);
          importedPath.has(importPath);
        }
        if (lines[lineNumber] === "") {
          lines[lineNumber] = EMPTY_LINE_TAG;
        }
        hasChangedText = true;
      } else if (
        (formatLine.startsWith("const") || formatLine.startsWith("let")) &&
        (formatLine.endsWith("EpmpUtils;") ||
          formatLine.endsWith("epmp.EpmpUtils;"))
      ) {
        const utils = lines[lineNumber].split("{")[1].split("}")[0].split(",");
        const referUtils = [];
        const commonUtils = [];
        for (const u of utils) {
          if (
            [
              "getLargeDocRefer",
              "getLargeDocReferDimHierArr",
              "getLargeDocReferDimDefArr",
              "getUapRef",
              "registerLargeDocValue",
            ].includes(u.trim())
          ) {
            referUtils.push(u);
          } else {
            commonUtils.push(u);
          }
        }
        if (referUtils.length > 0) {
          const importPath = "epmp/common/utils/refer";
          if (importedPath.has(importPath)) {
            continue;
          }
          lines[firstCodeLine] = `import {${referUtils.join(
            ","
          )}} from "${importPath}";\r\n${lines[firstCodeLine]}`;
          addImportInfoToConfig(importPath, dependModuleName, dependjs);
          importedPath.add(importPath);
        }
        if (commonUtils.length > 0) {
          lines[lineNumber] = `const {${commonUtils.join(",")}} = $util`;
        } else {
          lines[lineNumber] = EMPTY_LINE_TAG;
        }
        hasChangedText = true;
      } else if (
        (formatLine.startsWith("const") || formatLine.startsWith("let")) &&
        (line.endsWith("EpmpConst;") || line.endsWith("epmp.EpmpConst;"))
      ) {
        const constants = line.split("{")[1].split("}")[0].split(",");
        dealConstImport(constants);

        lines[lineNumber] = dealConstImport(constants);
        hasChangedText = true;
      } else {
        if (formatLine.indexOf("epmp.EpmpUtils") >= 0) {
          lines[lineNumber] = line.replace("epmp.EpmpUtils", "$util");
          hasChangedText = true;
        }
        if (formatLine.indexOf("epmp.EpmpConst") >= 0) {
          lines[lineNumber] = line.replace("epmp.EpmpConst", "$const");
          hasChangedText = true;
        }
        if (line.indexOf("<epmp.CheckboxTitle") >= 0) {
          const importPath = "epmp/common/components/CheckboxTitle";
          if (importedPath.has(importPath)) {
            continue;
          }
          lines[lineNumber] = lines[lineNumber].replace(
            "epmp.CheckboxTitle",
            "CheckboxTitle"
          );
          lines[
            firstCodeLine
          ] = `import CheckboxTitle from "${importPath}";\r\n${lines[firstCodeLine]}`;
          addImportInfoToConfig(importPath, dependModuleName, dependjs);
          importedPath.add(importPath);
          hasChangedText = true;
        }
        if (line.indexOf("webpackChunkName") >= 0 && line.indexOf("import(") >= 0) {
          const relativePath = line.split('/* webpackMode: "eager" */')[1].split(")")[0].replaceAll("'", "\"").split("\"")[1];
          dealRelativePath(formatPath, relativePath, dependModuleName, dependjs, analysisedFile, log, lineNumber, lines, importedPath, logFilePath, line, () => {
            hasChangedText = true;
          });
        }
      }
    }
    if (hasChangedText) {
      const newJScript = lines.filter((l) => l !== EMPTY_LINE_TAG).join("\r\n");
      fs.writeFileSync(filePath, newJScript);
    }
  } catch (e) {
    consoleLog(`>>>>ERROR<<<<解析${logFilePath}文件出错，错误信息：${e}`);
  }
}

function dealRelativePath(formatPath, importPath, dependModuleName, dependjs, analysisedFile, log, lineNumber, lines, importedPath, logFilePath, singleLineImport, sigChangeFlag) {
  let importAbsPath = path.resolve(path.dirname(formatPath), importPath);
  importAbsPath = importAbsPath.replaceAll("epmp\\public", "epmp\\common");
  if (!path.extname(importAbsPath)) {
    importAbsPath = path.resolve(importAbsPath, "index.js");
    if (!fs.existsSync(importAbsPath)) {
      importAbsPath = `${path.dirname(importAbsPath)}.js`;
    }
  }
  if (path.extname(importAbsPath) === ".js") {
    if (importAbsPath.indexOf("epmp\\common") < 0 || isInSameEntry(formatPath.replaceAll("\\", "/"), importAbsPath.replaceAll("\\", "/"))) {
      //相对路径引用非公共组件
      analysisFile(
        importAbsPath,
        dependModuleName,
        dependjs,
        analysisedFile,
        log
      );
    } else {
      //相对路径引用公共组件
      let compP = path.dirname(importAbsPath).split("\\src\\")[1];
      if (importAbsPath.indexOf("epmp\\common\\const") >= 0) {
        //相对引用了public下的const，直接使用$const中的变量，不再继续解析
        if (singleLineImport.indexOf("{") >= 0) {
          const constants = singleLineImport.split('{')[1].split('}')[0].split(',');
          lines[lineNumber] = dealConstImport(constants);
          sigChangeFlag();
        } else {
          consoleLog(`第${lineNumber}行，${formatPath}相对导入了公共const，且没有使用解构语法，需要手动再修改文件`);
        }
        
      } else if (compP.split("\\").length === 4) {
        consoleLog(`第${lineNumber + 1}行${logFilePath}相对导入了${importPath}`);
        importPath = compP.split("\\").join("/");
        const importParts = singleLineImport.split('"');
        importParts[1] = importPath;
        lines[lineNumber] = importParts.join('"');
        sigChangeFlag();
        addImportInfoToConfig(importPath, dependModuleName, dependjs);
      } else {
        //特殊处理，util的话，直接把 import { xxx } from "xxxx";改为const {xxx} = $util;
        if (compP.indexOf("epmp\\common\\utils") >= 0) {
          if (singleLineImport.indexOf(" from ") > 0 && singleLineImport.indexOf('{') > 0) {
            const utils = singleLineImport.split('{')[1].split('}')[0];
            lines[lineNumber] = `const { ${utils} } = $util;`;
            sigChangeFlag();
          } else {
            lines[lineNumber] = EMPTY_LINE_TAG;
            sigChangeFlag();
          }
        } else {
          consoleLog(
            `第${lineNumber + 1}行${logFilePath}相对引用了public目录下的${compP},删掉这一行`
          );
          if (compP.indexOf("centerReport\\public\\components") >= 0 || compP.indexOf("epmp\\common\\components") >= 0) {
            //引用了公共组件
            const componentName = compP.split("\\components\\")[1];
            let importPath = `epmp/common/components/${componentName}`;
            let dirnames = importPath.replaceAll("\\", "/").split("/");
            dirnames.length = 4;
            importPath = dirnames.join("/");
            if (!importedPath.has(importPath)) {
              if (singleLineImport.indexOf(" from ") >= 0) {
                let importShortArr = singleLineImport.split(" from ");
                importShortArr[1] = `"${importPath}"`;
                lines[lineNumber] = `${importShortArr.join(" from ")}\r\n`;
              } else {
                let importShortArr = singleLineImport.split(" ");
                importShortArr[1] = `"${importPath}"`;
                lines[lineNumber] = `${importShortArr.join(" ")}\r\n`; 
              }
              sigChangeFlag();
              addImportInfoToConfig(
                importPath,
                dependModuleName,
                dependjs
              );
              importedPath.add(importPath);
            }
          } else {
            lines[lineNumber] = EMPTY_LINE_TAG;
            sigChangeFlag();
          } 
        }
      }
    }
  }
}

/**
 *
 * @param short {string}
 * @return {boolean}
 */
function isLegalImport(short) {
  const stack = [];
  for (const c of short) {
    if (c === "{") {
      stack.push("{");
    } else if (c === "}" && stack[stack.length - 1] === "{") {
      stack.pop();
    }
  }
  return stack.length === 0;
}

/**
 *
 * @param str {string}
 */
function formatImport(str) {
  /** @type string*/
  let importShort = str
    .replace(/{/g, " {")
    .replace(/}/g, "} ")
    .replace(/\s+/g, " ")
    .replace(/{\s/g, "{")
    .replace(/,}/g, "}")
    .replace(/\s}/g, "}")
    .replace(/'/g, '"');
  if (!importShort.endsWith(";")) {
    importShort = `${importShort};`;
  }
  return importShort;
}

/**
 *
 * @param line {string}
 */
function getFormatLine(line) {
  if (line.endsWith(";")) {
    return line.trim();
  }
  return `${line};`.trim();
}

/**
 *
 * @param str {string}
 */
function analysisImportShort(str) {
  let [imports, from] = str.split("import")[1].split("from");
  imports.trim();
  from.trim();
  from = from.split('"')[1];
}

/**
 *
 * @param importShort {string}
 */
function getImportPath(importShort) {
  let from = "";
  importShort = importShort.trim().substring(7).trim();
  if (importShort.indexOf(" from ") > 0) {
    from = importShort.split(" from ")[1];
  } else {
    from = importShort;
  }
  from.trim();
  return from.split('"')[1];
}

/**
 *
 * @param log {string}
 */
function writeLog(log) {
  fs.writeFileSync(path.resolve(__dirname, "log.txt"), `${log}\n`);
}

function consoleLog(...msg) {
  if (!consoleLog.logs) {
    consoleLog.logs = [];
  }
  consoleLog.logs.push(msg.join(''));
  // console.log(...msg);
  clearTimeout(consoleLog.timer);
  consoleLog.timer = setTimeout(() => {
  fs.writeFileSync(
    path.resolve(__dirname, "console.txt"),
    consoleLog.logs.join("\n")
  );
  }, 1000);
}

function addImportInfoToConfig(importPath, dependModuleName, dependjs) {
  dependModuleName.add(importPath);
  const importAbsPath = path.resolve(rootPath, importPath, "index.js");
  let compDjs = [];
  if (
    //导入了公共组件，读取dependjs
    importAbsPath.indexOf("epmp\\common\\components") >= 0 ||
    //导入了refer工具函数，读取dependjs
    importAbsPath.indexOf("epmp\\common\\utils\\refer\\index.js") >= 0 ||
    //导入了centerReport，读取dependjs
    importAbsPath.indexOf("epmp\\common\\centerReport") >= 0
  ) {
    const configJSON = require(path.resolve(
      path.dirname(importAbsPath),
      "config.json"
    ));
    const dependjs = configJSON.dependjs
      ? Array.isArray(configJSON.dependjs)
        ? configJSON.dependjs
        : [configJSON.dependjs]
      : [];
    compDjs.push(...dependjs);
  }
  for (const djs of compDjs) {
    dependjs.add(djs);
  }
  dependjs.add(`../../../../${importPath}/index.js`);
}

function isInSameEntry(filePath, importAbsPath) {
  const fps = filePath.split("/src/")[1].split("/");
  const ips = importAbsPath.split("/src/")[1].split("/");
  return fps[0] === ips[0] && fps[1] === ips[1] && fps[2] === ips[2] && fps[3] === ips[3];
}

function dealConstImport(constants) {
  let lineText = "";
  const REG_cst = constants.filter((v) =>
    [
      "charReg",
      "checkChineseReg",
      "fileNameRegXLSX",
      "fileNameRegXLSX_length",
      "noIllegalPlusReg",
      "noIllegalPlusReg2",
      "noIllegalPlusReg3",
      "noIllegalPlusReg3_length",
      "noIllegalPlusReg4",
      "noIllegalPlusReg5",
      "noIllegalPlusReg6",
      "noIllegalPlusReg7",
      "noIllegalPlusReg7_length",
      "noIllegalReg",
      "numCharPlusAndNonumstartReg",
      "numCharPlusReg",
      "numCharPlusReg2",
      "numCharPlusRegAS",
      "numCharPlusRegMD",
      "numCharReg",
      "numReg",
    ].includes(v.trim())
  );
  const VALUE_cst = constants.filter((v) =>
    [
      "CALCULATE_ALL",
      "CALCULATE_MULTI",
      "CALCULATE_RULE",
      "CALCULATE_SHEET",
      "CUST_DIMLEVEL",
      "DIMDEF_TIME",
      "FETCH_DATA",
      "GlobalCode",
      "GroupCode",
      "LARGE_SORT_DIMHIER",
      "LARGE_SORT_DIMLEVEL",
      "OUTSYS_CUST_DIMHIER",
      "UAP_CUST_DIMHIER",
    ].includes(v.trim())
  );
  const SPELL_cst = constants.filter((v) =>
    ["warning", "success", "danger", "add", "edit", "browse"].includes(
      v.trim()
    )
  );
  if (REG_cst.length > 0) {
    lineText += `const {${REG_cst.join(",")}} = $const.REG;\r\n`;
  }
  if (VALUE_cst.length > 0) {
    lineText += `const {${VALUE_cst.join(",")}} = $const.VALUE;\r\n`;
  }
  if (SPELL_cst.length > 0) {
    lineText += `const {${SPELL_cst.join(",")}} = $const.SPELL;\r\n`;
  }
  
  return lineText;
}